package com.xinsoft.controller.wms;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xinsoft.common.Response;
import com.xinsoft.constant.Const;
import com.xinsoft.entity.dto.*;
import com.xinsoft.entity.po.ScmPushBill;
import com.xinsoft.entity.po.ScmStock;
import com.xinsoft.entity.po.SysWarehouseItem;
import com.xinsoft.service.ScmPushBillService;
import com.xinsoft.service.ScmStockService;
import com.xinsoft.service.SysWarehouseItemService;
import com.xinsoft.service.impl.SyncPullBillAdapter;
import com.xinsoft.service.impl.SyncPushBillAdapter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 推送单据
 *
 * @folder 华德/云供应链/仓库管理/推送单据
 */
@Slf4j
@RestController
@RequestMapping("/scm/pushBill")
public class ScmPushBillController {

    @Autowired
    private ScmPushBillService pushBillService;
    @Autowired
    private SyncPushBillAdapter syncPushBillAdapter;
    @Autowired
    private SyncPullBillAdapter syncPullBillAdapter;
    @Autowired
    private SysWarehouseItemService warehouseItemService;
    @Autowired
    private ScmStockService stockService;


    /**
     * 待提交的单据列表
     *
     * @param param
     * @return {@link Response}<{@link ?}>
     */
    @PostMapping("/list")
    public Response<?> list(@RequestBody ScmPushBillParam param) {
        List<ScmPushBill> list = pushBillService.list(Wrappers.lambdaQuery(ScmPushBill.class)
                .eq(Objects.nonNull(param.getBillType()), ScmPushBill::getBillType, param.getBillType())
                .eq(Objects.nonNull(param.getSourceId()), ScmPushBill::getSourceId, param.getSourceId())
                .eq(ScmPushBill::getStatus, 0));
        SysWarehouseItemParam warehouseItemParam = new SysWarehouseItemParam();
        warehouseItemParam.setCurrentPage(1);
        warehouseItemParam.setPageSize(-1);
        IPage<SysWarehouseItem> pageListByParam = (IPage<SysWarehouseItem>) warehouseItemService.findPageListByParam(warehouseItemParam);
        Map<String, SysWarehouseItem> warehouseItemMap = pageListByParam.getRecords().stream().collect(Collectors.toMap(item -> String.join("_", item.getWarehouseId().toString(), item.getId().toString()), item -> item));

        List<Map> erpInOrOutStockParamList = new ArrayList<>();
        List<String> jsonParamList = list.stream().map(ScmPushBill::getJsonParam).collect(Collectors.toList());
        jsonParamList.forEach(item -> {
            List<Map> erpInOrOutStockParams = JSON.parseArray(item, Map.class);
            erpInOrOutStockParams.forEach(map -> {
                // erp实时库存查询
                ErpRealTimePageParam erpRealTimePageParam = new ErpRealTimePageParam();
                erpRealTimePageParam.setCurrentPage(1);
                erpRealTimePageParam.setPageSize(1000);
                erpRealTimePageParam.setMaterialId(map.get("materialId").toString());
                erpRealTimePageParam.setBatch(map.get("batch").toString());
                erpRealTimePageParam.setStockId((Integer) map.get("warehouseId"));
                erpRealTimePageParam.setStockLocationId((Integer) map.get("warehItemId"));
                List<ErpRealTimeDto> records = syncPullBillAdapter.realtimeInventory(erpRealTimePageParam).getRecords();
                map.put("num", records.get(0).getNum());
                String key = String.join("_", map.get("warehouseId").toString(), map.get("warehItemId").toString());
                SysWarehouseItem sysWarehouseItem = warehouseItemMap.get(key);
                map.put("warehouseName", sysWarehouseItem.getWarehouseName());
                map.put("warehouseItemName", sysWarehouseItem.getWhItemName());
            });

            erpInOrOutStockParamList.addAll(erpInOrOutStockParams);
        });
        Map<String, Object> map = new HashMap<>();
        map.put("billType", param.getBillType());
        map.put("sourceId", param.getSourceId());
        map.put("erpInOrOutStockParamList", erpInOrOutStockParamList);
        return Response.succeed(map);
    }

    // /**
    //  * 提交单据推送金蝶
    //  *
    //  * @param map 单据列表
    //  * @return {@link Response}<{@link ?}>
    //  */
    // @PostMapping("/submit")
    // public Response<?> submit(@RequestBody Map<String, Object> map) {
    //     Integer billType = (Integer) map.get("billType");
    //     Integer sourceId = (Integer) map.get("sourceId");
    //     List<ErpInOrOutStockParam> params = JSON.parseArray(JSON.toJSONString(map.get("erpInOrOutStockParamList")), ErpInOrOutStockParam.class);
    //     Response<?> response = Response.succeed();
    //     // 推送单据到金蝶
    //     if (Objects.equals(billType, 10883)) {
    //         response = syncPushBillAdapter.feedingOutStock(params);
    //     }
    //     // 更新暂存的单据状态
    //     pushBillService.update(Wrappers.lambdaUpdate(ScmPushBill.class)
    //             .set(ScmPushBill::getStatus, 1)
    //             .eq(ScmPushBill::getBillType, billType)
    //             .eq(ScmPushBill::getSourceId, sourceId));
    //     return response;
    // }

    /**
     * 暂存待推送单据
     * @param dto
     * @return {@link Response}<{@link ?}>
     */
    @PostMapping("/tempSave")
    @Transactional(rollbackFor = Exception.class)
    public Response<?> tempSave(@Validated @RequestBody PushBillDTO dto){
        ScmPushBill pushBill = new ScmPushBill();
        pushBill.setBillType(dto.getBillType());
        pushBill.setSourceId(dto.getSourceId());
        pushBill.setSourceItemId(dto.getSourceItemId());
        pushBill.setMaterialId(dto.getMaterialId());
        pushBill.setJsonParam(JSON.toJSONString(dto.getErpInOrOutStockParamList()));
        pushBillService.save(pushBill);
        return Response.succeed();
    }

    /**
     * 提交单据推送金蝶
     * 根据单据类型和源单id推送
     *
     * @param param
     * @return {@link Response}<{@link ?}>
     */
    @PostMapping("/submit")
    @Transactional(rollbackFor = Exception.class)
    public Response<?> submit(@RequestBody ScmPushBillParam param) {
        if (Objects.isNull(param.getBillType())) {
            return Response.fail("单据类型不能为空");
        }
        if (Objects.isNull(param.getSourceId())) {
            return Response.fail("源单id不能为空");
        }
        // 1.获取需要推送金蝶的数据
        List<ScmPushBill> list = pushBillService.list(Wrappers.lambdaQuery(ScmPushBill.class)
                .eq(Objects.nonNull(param.getBillType()), ScmPushBill::getBillType, param.getBillType())
                .eq(Objects.nonNull(param.getSourceId()), ScmPushBill::getSourceId, param.getSourceId())
                .eq(ScmPushBill::getStatus, 0));
        if (CollectionUtil.isEmpty(list)) {
            return Response.fail("没有暂存的数据，无需提交");
        }
        List<ErpInOrOutStockParam> erpInOrOutStockParamList = new ArrayList<>();
        List<String> jsonParamList = list.stream().map(ScmPushBill::getJsonParam).collect(Collectors.toList());
        jsonParamList.forEach(item -> {
            List<ErpInOrOutStockParam> erpInOrOutStockParams = JSON.parseArray(item, ErpInOrOutStockParam.class);

            erpInOrOutStockParamList.addAll(erpInOrOutStockParams);
        });


        // 2.推送单据到金蝶
        Response<?> response = Response.succeed();
        // 生产领用出库
        if (Objects.equals(param.getBillType(), Const.BillType.SCLYCK)) {
            response = syncPushBillAdapter.feedingOutStock(erpInOrOutStockParamList);
        }
        // 委外领用出库
        if (Objects.equals(param.getBillType(), Const.BillType.WWLYCK)) {
            response = syncPushBillAdapter.sourcingFeedingOutStock(erpInOrOutStockParamList);
        }
        // 销售出库
        if (Objects.equals(param.getBillType(),Const.BillType.XSCK)){
            Map<String, ScmStock> stockMap = this.getStockMap(erpInOrOutStockParamList);
            if (Objects.nonNull(stockMap)){
                // 非null为生产入库的产品需更新可用数量，用于消息提醒长时间未使用
                List<ScmStock> scmStockList = new ArrayList<>();
                erpInOrOutStockParamList.forEach(item -> {
                    String key = String.join("_", item.getMaterialId().toString(), item.getBatch(), item.getWarehouseId().toString(), item.getWarehItemId().toString());
                    ScmStock stock = null;
                    if (stockMap.containsKey(key)) {
                        stock = stockMap.get(key);
                        stock.setBatchNumFree(stock.getBatchNumFree().subtract(item.getQty()));
                        scmStockList.add(stock);
                    }
                });
                stockService.updateBatchById(scmStockList);
            }
            response = syncPushBillAdapter.saleOutStock(erpInOrOutStockParamList);
        }

        // 3.更新暂存的单据状态
        pushBillService.update(Wrappers.lambdaUpdate(ScmPushBill.class)
                .set(ScmPushBill::getStatus, 1)
                .eq(ScmPushBill::getBillType, param.getBillType())
                .eq(ScmPushBill::getSourceId, param.getSourceId()));
        return response;
    }

    /**
     * 获取库存记录
     * @param params
     * @return {@link Map}<{@link String}, {@link ScmStock}>
     */
    public Map<String, ScmStock> getStockMap(List<ErpInOrOutStockParam> params){
        List<Integer> materialIds = params.stream().map(ErpInOrOutStockParam::getMaterialId).distinct().collect(Collectors.toList());
        List<String> batchs = params.stream().map(ErpInOrOutStockParam::getBatch).distinct().collect(Collectors.toList());
        List<Integer> warehouseIds = params.stream().map(ErpInOrOutStockParam::getWarehouseId).distinct().collect(Collectors.toList());
        List<Integer> warehouseItemIds = params.stream().map(ErpInOrOutStockParam::getWarehItemId).distinct().collect(Collectors.toList());
        List<ScmStock> stockList = stockService.list(Wrappers.lambdaQuery(ScmStock.class)
                .in(ScmStock::getMaterialId, materialIds)
                .in(ScmStock::getBatchNo, batchs)
                .in(ScmStock::getWarehouseId, warehouseIds)
                .in(ScmStock::getWarehItemId, warehouseItemIds));
        if (CollectionUtil.isNotEmpty(stockList)){
            return stockList.stream().collect(Collectors.toMap(s -> String.join("_", s.getMaterialId().toString(), s.getBatchNo(), s.getWarehouseId().toString(), s.getWarehItemId().toString()), s -> s));
        }
        return null;
    }
}
